/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hotgammon.domain.game;

import hotgammon.domain.GameListener;
import hotgammon.domain.board.Board;
import hotgammon.domain.board.Color;
import hotgammon.domain.board.Location;
import hotgammon.domain.board.StandardBoard;
import hotgammon.domain.game.dice.DiceStrategy;
import hotgammon.domain.game.move.MoveStrategy;
import hotgammon.domain.game.winner.WinnerStrategy;
import java.util.ArrayList;
import java.util.Iterator;

/**
 *
 * @author truck
 */
public class StandardGame implements Game {
    
    private Board board;
    private int[] diceLeft;
    private int[] thrownDice;
    private Color playerInTurn;
    private Color lastPlayer;
    private MoveStrategy moveStrat;
    private DiceStrategy diceStrat;
    private WinnerStrategy winnerStrat;
    private GameFactory gameFactory;
    private boolean newGame = false;
    private ArrayList<GameListener> gameListeners;
    
    public StandardGame(GameFactory gameFactory) {
        lastPlayer = Color.NONE;
        playerInTurn = Color.NONE;
        board = new StandardBoard();
        thrownDice = new int[0];
        //Added for factory pattern
        this.gameFactory = gameFactory;
        moveStrat = gameFactory.createMoveStrategy();
        diceStrat = gameFactory.createDiceStrategy();
        winnerStrat = gameFactory.createWinnerStrategy();
        gameListeners = new ArrayList<GameListener>();
        
    }

    /**
     * throw dice
     */
    private void throwDice() {
        thrownDice = diceStrat.throwDice();
        diceLeft = thrownDice.clone();
        for (GameListener gl : gameListeners) {
            gl.diceRolled();
        }
    }

    public void newGame() {
        newGame = true;
        // TUE FIX(!) BEGIN
        //diceStrat.resetCounter();
        diceStrat = gameFactory.createDiceStrategy();
        // TUE FIX(!) END
        playerInTurn = Color.NONE;
        lastPlayer = Color.NONE;
        winnerStrat = gameFactory.createWinnerStrategy();
        board.reset();
        for (GameListener gl : gameListeners) {
            gl.boardChange();
        }

    }

    public void nextTurn() {
        throwDice();

        if (lastPlayer == Color.BLACK) {
            playerInTurn = Color.RED;
            lastPlayer = Color.RED;
        } 
        else if (lastPlayer == Color.RED){
            playerInTurn = Color.BLACK;
            lastPlayer = Color.BLACK;
        }
        // Looks for a player from the eyes of the dice
        if (newGame) {
            int firstDie = diceLeft[0];
            int secondDie = diceLeft[1];
            if (firstDie > secondDie) {
                playerInTurn = Color.RED;
                lastPlayer = Color.RED; 
            }
            if (firstDie < secondDie) {
                playerInTurn = Color.BLACK;
                lastPlayer = Color.BLACK; 
            }
            newGame = false;
        }
    }


    public boolean move(Location from, Location to) {
        if (!(moveStrat.isValidMove(board, from, to, thrownDice, playerInTurn))) {
            return false;
        }
        //if the player beats the opponents checker, the checker beaten must be moved to his bar
        if (board.getColor(to) == board.getColor(from) || board.getColor(to) == Color.NONE) {
            //no kill just move
            board.move(from, to);
        } else if (board.getCount(to) == 1) {
            //moves the one beated to BAR
            Color otherPlayer = board.getColor(to);
            if (otherPlayer == Color.BLACK) {
                board.move(to, Location.B_BAR);
            } else {
                board.move(to, Location.R_BAR);
            }
            board.move(from, to);
        }
        thrownDice = moveStrat.removeDice(thrownDice, from, to);
        if (thrownDice.length == 0) {
            playerInTurn = Color.NONE;
        }
        for (GameListener gl : gameListeners) {
            gl.boardChange();
        }
        
        return true;
    }

    public Color getPlayerInTurn() {
        return playerInTurn;
    }

    public int getNumberOfMovesLeft() {
        return thrownDice.length;
    }

    public int[] diceThrown() {
        return thrownDice;
    }

    public int[] diceValuesLeft() {
        return diceLeft;
    }

    public Color winner() {
        return winnerStrat.getWinner(board);
    }

    public Iterator<Location> boardIterator() {
        return board.iterator();
    }

    public Color getColor(Location location) {
        return board.getColor(location);
    }

    public int getCount(Location location) {
        return board.getCount(location);
    }

    public void addGameListener(GameListener gl) {
        gameListeners.add(gl);
    }

     
}
